package qc.module.qms.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import qc.common.core.constants.QmsCacheConstant;
import qc.common.core.enums.qms.QmsElementValueDataTypeEnum;
import qc.common.core.exception.QCPromptException;
import qc.common.core.unify.QCUnifyReturnValue;
import qc.module.qms.dto.element.ElementDto;
import qc.module.qms.entity.QmsElement;
import qc.module.qms.mapper.ElementMapper;
import qc.module.qms.repository.QmsElementRepository;

import java.util.List;

/**
 * QMS监测要素Service
 *
 * @author QuCheng Tech
 * @since 2025/9/29
 */
@Service
public class QmsElementService {
    private static final Logger logger = LoggerFactory.getLogger(QmsElementService.class);

    private static final String Cache_Key_Element = QmsCacheConstant.CACHE_KEY_ELEMENT_ENTITY;

    @Autowired
    private QmsElementRepository repository;

    /**
     * 更新缓存，不管是否有缓存数据都进行更新
     *
     * @return java.util.List<qc.module.qms.entity.QmsElement>
     * @author QuCheng Tech
     * @since 2025/9/11
     */
    @CachePut(value = Cache_Key_Element)
    public List<QmsElement> cachePut() {
        logger.debug("cachePut");

        return getAllFromDb();
    }

    /**
     * 清除缓存
     *
     * @author QuCheng Tech
     * @since 2025/9/11
     */
    @CacheEvict(value = Cache_Key_Element)
    public void cacheEvict() {
        logger.debug("cacheEvict");
    }

    /**
     * 获取全部；有缓存时从缓存获取，没有缓存时从数据库中获取并放入缓存
     *
     * @return java.util.List<qc.module.qms.entity.QmsElement>
     * @author QuCheng Tech
     * @since 2025/9/11
     */
    @Cacheable(value = Cache_Key_Element)
    public List<QmsElement> getAllWithCache() {
        logger.debug("getAll");

        return getAllFromDb();
    }

    /**
     * 从数据库中获取全部
     *
     * @return java.util.List<qc.module.qms.entity.QmsElement>
     * @author QuCheng Tech
     * @since 2025/9/11
     */
    public List<QmsElement> getAllFromDb() {
        logger.debug("getAllFromDb 从数据库中查询所有监测要素信息");
        LambdaQueryWrapper<QmsElement> wrapper = new LambdaQueryWrapper<>();

        //排序，按监测要素编码
        wrapper.orderByAsc(QmsElement::getElecode);

        //查询数据
        return repository.selectList(wrapper);
    }

    /**
     * 根据监测要素编码查询监测要素信息
     *
     * @param elecode 监测要素编码
     * @return ElementDto 监测要素信息
     */
    public ElementDto get(String elecode) throws QCPromptException {
        // 参数校验：指定的监测要素编码不为空
        if (StringUtils.isBlank(elecode)) {
            throw new QCPromptException("要素编码不能为空");
        }

        // 查询指定要素编码的监测要素
        LambdaQueryWrapper<QmsElement> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(QmsElement::getElecode, elecode);
        QmsElement element = repository.selectOne(wrapper);
        if (element != null)
            return ElementMapper.MAPPER.toDto(element);

        //throw new QCPromptException("指定的监测要素[" + elecode + "]不存在");
        return null;
    }

    /**
     * 添加监测要素信息
     *
     * @param dto 监测要素信息
     * @return String 成功返回null，失败返回错误信息
     */
    public String add(ElementDto dto) {
        // 1. 基础参数校验
        if (dto == null) {
            return QCUnifyReturnValue.Warn("监测要素信息不能为空");
        }
        if (StringUtils.isBlank(dto.getElecode())) {
            return QCUnifyReturnValue.Warn("要素编码不能为空，请输入要素编码");
        }
        if (StringUtils.isBlank(dto.getElename())) {
            return QCUnifyReturnValue.Warn("要素名称不能为空，请输入要素名称");
        }
        // 3. 唯一性校验
        if (isElementCodeExist(dto.getElecode())) {
            return QCUnifyReturnValue.Warn("要素编码[" + dto.getElecode() + "]已存在，请重新输入");
        }
        //判断监测要素名称是否已被其他监测要素使用（排除自身）
        if (isElementNameExist(dto.getElename(), dto.getElecode())) {
            return QCUnifyReturnValue.Warn("要素名称[" + dto.getElename() + "]已存在，请重新输入");
        }
        // 4. 数据格式校验：如果传入的分辨力不为空判断是否能转换为数字，数字必须大于0
        String resolutionValidationResult = validateResolution(dto.getResolution());
        if (resolutionValidationResult != null)
            return resolutionValidationResult;
        //如果有传入上限或者下限，必须能转换为数字；上限必须＞下限
        String limitsValidationResult = validateLimits(dto.getMaxv(), dto.getMinv());
        if (limitsValidationResult != null)
            return limitsValidationResult;

        //DTO转换为Entity，转换后判断数据值类型枚举是否正确
        QmsElement en = ElementMapper.MAPPER.dtoToEntity(dto);
        if (en.getValuetype() == QmsElementValueDataTypeEnum.UN_DEFINE)
            return QCUnifyReturnValue.Warn("数据值类型无效，请输入有效的数据值类型");

        if (repository.insert(en) < 0x1)
            return QCUnifyReturnValue.Warn("新增监测要素[" + dto.getElename() + "]失败");

        return QCUnifyReturnValue.Success();
    }

    /**
     * 修改监测要素信息
     *
     * @param dto 监测要素DTO
     * @return String 成功返回null，失败返回错误信息
     */
    public String update(ElementDto dto) {
        // 1. 基础参数校验
        if (dto == null) {
            return QCUnifyReturnValue.Warn("监测要素信息不能为空");
        }
        if (StringUtils.isBlank(dto.getElecode())) {
            return QCUnifyReturnValue.Warn("要素编码不能为空，请输入要素编码");
        }
        if (StringUtils.isBlank(dto.getElename())) {
            return QCUnifyReturnValue.Warn("要素名称不能为空，请输入要素名称");
        }
        // 2. 存在性校验
        if (!isElementCodeExist(dto.getElecode())) {
            return QCUnifyReturnValue.Warn("要修改的监测要素[" + dto.getElecode() + "]不存在，请确认要素编码是否正确");
        }
        // 3. 判断监测要素名称是否已被其他监测要素使用（排除自身）
        if (isElementNameExist(dto.getElename(), dto.getElecode())) {
            return QCUnifyReturnValue.Warn("要素名称[" + dto.getElename() + "]已存在，请重新输入");
        }
        // 5. 数据格式校验：如果传入的分辨力不为空判断是否能转换为数字，数字必须大于0
        String resolutionValidationResult = validateResolution(dto.getResolution());
        if (resolutionValidationResult != null)
            return resolutionValidationResult;
        //如果有传入上限或者下限，必须能转换为数字；上限必须＞下限
        String limitsValidationResult = validateLimits(dto.getMaxv(), dto.getMinv());
        if (limitsValidationResult != null)
            return limitsValidationResult;

        //DTO转换为Entity，转换后判断数据值类型枚举是否正确
        QmsElement en = ElementMapper.MAPPER.dtoToEntity(dto);
        if (en.getValuetype() == QmsElementValueDataTypeEnum.UN_DEFINE)
            return QCUnifyReturnValue.Warn("数据值类型无效，请输入有效的数据值类型");

        if (repository.updateById(en) < 0x1)
            return QCUnifyReturnValue.Warn("修改监测要素[" + dto.getElename() + "]失败");

        return QCUnifyReturnValue.Success();
    }

    /**
     * 删除指定要素信息
     *
     * @param elecode 要素编码
     * @return String 删除成功返回null，删除失败返回错误信息
     */
    public String delete(String elecode) {
        //指定的监测要素编码为空的不需要进行删除操作
        if (StringUtils.isNotBlank(elecode))
            repository.deleteById(elecode);

        return QCUnifyReturnValue.Success();
    }

    /**
     * 检查指定要素名称是否存在（排除自身）
     *
     * @param elename        要素名称
     * @param excludeElecode 排除的要素编码
     * @return true表示存在，false表示不存在
     */
    private boolean isElementNameExist(String elename, String excludeElecode) {
        //指定的监测要素编码为空的不需要进行查询是否存在
        if (StringUtils.isNotBlank(elename)) {
            LambdaQueryWrapper<QmsElement> wrapper = new LambdaQueryWrapper<>();
            wrapper.select(QmsElement::getElecode); // 只查询必要字段
            wrapper.eq(QmsElement::getElename, elename);//监测要素名称相等
            if (StringUtils.isNotBlank(excludeElecode))
                wrapper.ne(QmsElement::getElecode, excludeElecode);//监测要素编码不等

            // 使用selectCount替代selectOne，进一步减少数据传输
            return repository.selectCount(wrapper) > 0;
        }

        return false;
    }

    /**
     * 检查指定要素编码是否存在
     *
     * @param elecode 要素编码
     * @return boolean true表示存在，false表示不存在
     */
    private boolean isElementCodeExist(String elecode) {
        if (StringUtils.isBlank(elecode)) {
            return false;
        }
        LambdaQueryWrapper<QmsElement> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(QmsElement::getElecode);
        wrapper.eq(QmsElement::getElecode, elecode);
        return repository.selectCount(wrapper) > 0;
    }

    /**
     * 验证分辨力值是否有效，如果传入的分辨力不为空判断是否能转换为数字，数字必须大于0
     *
     * @param resolution 分辨力字符串
     * @return 验证结果，null表示验证通过，其他表示错误信息
     */
    private String validateResolution(String resolution) {
        if (StringUtils.isNotBlank(resolution)) {
            try {
                double resolutionValue = Double.parseDouble(resolution);
                if (resolutionValue <= 0) {
                    return QCUnifyReturnValue.Warn("分辨力必须大于0");
                }
            } catch (NumberFormatException e) {
                return QCUnifyReturnValue.Warn("分辨力格式不正确，请输入有效的数字");
            }
        }

        return QCUnifyReturnValue.Success();
    }

    /**
     * 验证上下限数值是否有效，如果有传入上限或者下限，必须能转换为数字；上限必须＞下限
     *
     * @param maxv 数值上限
     * @param minv 数值下限
     * @return 验证结果，null表示验证通过，其他表示错误信息
     */
    private String validateLimits(String maxv, String minv) {
        //先初始化最大和最小值为NaN，如果2个值均有效时判断上限＞下限
        double min = Double.NaN;
        double max = Double.NaN;
        if (StringUtils.isNotBlank(maxv)) {
            try {
                max = Double.parseDouble(maxv);
            } catch (NumberFormatException e) {
                return QCUnifyReturnValue.Warn("上限值不能转换为有效的数值");
            }
        }
        if (StringUtils.isNotBlank(minv)) {
            try {
                min = Double.parseDouble(minv);
            } catch (NumberFormatException e) {
                return QCUnifyReturnValue.Warn("下限值不能转换为有效的数值");
            }
        }
        //如果同时有上限和下限值，判断是否上限＞下限
        if (Double.isNaN(min) == false && Double.isNaN(max))
            return QCUnifyReturnValue.Warn("数值上限必须大于数值下限");

        return QCUnifyReturnValue.Success();
    }
}
